﻿#include "opencv2\opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
	const char* fn = "D:\\opencv class\\pic2.png";
	Mat image = imread(fn);
	imshow("原始图像", image);

	//转化为灰度图像
	Mat gray_image;
	cvtColor(image, gray_image, COLOR_BGR2GRAY);
	imshow("灰度图像", gray_image);
	//设定bin数目
	int histBinNum = 255;

	//设定取值范围
	float range[] = { 0, 255 };
	const float* histRange = { range };

	//声明三个通道的hist数组
	Mat hist;

	//  onst Mat* images：输入图像数组
	//	int nimages：输入图像数组中图像的个数
	//	const int* channels：输入图像数组中第几通道需要统计直方图（可以多个通道）
	//	InputArray mask：掩膜，，计算掩膜内的直方图  ...Mat()
	//	OutputArray hist:输出的直方图数组
	//	int dims：需要统计直方图通道的个数（可以多个通道）
	//	const int* histSize：指的是直方图分成多少个区间，就是 bin的个数
	//	const float** ranges： 统计像素值得区间
	//	bool uniform = true::是否对得到的直方图数组进行归一化处理
	//	bool accumulate = false：在多个图像时，是否累计计算像素值得个数
	calcHist(&gray_image, 1, 0, Mat(), hist, 1, &histBinNum, &histRange);

	double max;
	Point max_point;
	//获取直方图元素个数最多的区间
	minMaxLoc(hist, NULL, &max, NULL, &max_point);
	//创建直方图白色背景
	Mat histImg = Mat::zeros(256, 256, CV_8UC1);
	for (int i = 0; i < 255; i++)
	{
		//取每个bin的数目, 然后变换到0-255范围内
		int temp = (int)(hist.at<float>(i, 0) * 255. / max);

		//如果bin数目为0，则说明图像上没有该灰度值，则整列为黑色
		//如果图像上有该灰度值，则将该列对应个数的像素设为白色
		if (temp)
		{
			//由于图像坐标是以左上角为原点，所以要进行变换，使直方图图像以左下角为坐标原点
			histImg.col(i).rowRange(Range(255 - temp, 255)) = 255;
		}
	}
	imshow("直方图", histImg);

	cout << "直方图元素个数最多的区间：" << max_point.y << endl;


	Mat thershold_image;
	int thershold = threshold(gray_image, thershold_image, 0, 255, THRESH_OTSU);
	cout << "大津法阈值：" << thershold << endl;
	imshow("大津法", thershold_image);

	Mat mid_image;
	medianBlur(thershold_image, mid_image, 5);
	imshow("大津法--中值滤波", mid_image);

	//定义核
	Mat element = getStructuringElement(MORPH_RECT, Size(9, 9));
	//进行形态学开操作
	morphologyEx(mid_image, mid_image, CV_MOP_OPEN, element);
	imshow("开操作--大津法--中值滤波", mid_image);

	waitKey(0);
	destroyAllWindows();
}